package org.jslaughter.component.stats;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.jslaughter.event.eventtype.DamageEvent;
import org.nvframe.component.AbstractComponent;
import org.nvframe.component.physics.state.PhysicsPosition;
import org.nvframe.entity.Entity;
import org.nvframe.event.EventService;
import org.nvframe.event.eventtype.CollisionEvent;
import org.nvframe.event.eventtype.CollisionListener;
import org.nvframe.event.eventtype.UpdateEvent;
import org.nvframe.event.eventtype.UpdateListener;
import org.nvframe.manager.CollisionManager;
import org.nvframe.util.Settings;

/**
 * 
 * @author Nik Van Looy
 */
public class DamageOnCollisionTransmitter extends AbstractComponent implements CollisionListener, UpdateListener {
	
	private float minDamagePoints;
	private float maxDamagePoints;
	private boolean removeOnCollision;
	private int checkCollisionIntervalMs;
	private int checkCollisionDurationMs;
	private List<String> excludes = new ArrayList<String>();
	
	private int durationTimer;
	private int intervalTimer;
	private List<Entity> checkCollisionReceivers;

	public DamageOnCollisionTransmitter(String id, Entity owner, Settings settings) {
		super(id, owner);
		
		minDamagePoints = settings.getInt("minDamagePoints", 0);
		maxDamagePoints = settings.getInt("maxDamagePoints", 0);
		removeOnCollision = settings.getBoolean("removeOnCollision", false);
		checkCollisionIntervalMs = settings.getInt("checkCollisionIntervalMs", 0);
		checkCollisionDurationMs = settings.getInt("checkCollisionDurationMs", 0);
				
		if(settings.containsKey("excludes"))
			excludes.addAll(Arrays.asList(settings.getString("excludes", "").split(",")));

		intervalTimer = checkCollisionIntervalMs + 1;
		durationTimer = 0;
		
		checkCollisionReceivers = new ArrayList<Entity>();
		
		EventService.getInstance().addEventListener(this);
	}
	
	public int calculateDamagePoints() {
		return (int) Math.round((Math.random() * (maxDamagePoints - minDamagePoints)) + minDamagePoints);
	}
	
	@Override
	public void onCollision(CollisionEvent event) {
		Entity receiver;
		
		// determine the receiver for the damage
		if(event.getEntity1() == owner)
			receiver = event.getEntity2();
		else
			receiver = event.getEntity1();
		
		// ignore collision from the exludes list
		for(String exclude : excludes)
			if(receiver.getId().toString().equals(exclude))
				return;
		
		// add colliding target to the continious check arraylist
		if(!checkCollisionReceivers.contains(receiver))
			checkCollisionReceivers.add(receiver);
		
		if(intervalTimer > checkCollisionIntervalMs) {
			
			// if in terval is 0 there will be no continious collision check
			if(checkCollisionIntervalMs != 0)
				intervalTimer = 0;
			
			EventService.getInstance().fireEvent(new DamageEvent(owner, receiver, calculateDamagePoints()));
			
			if(removeOnCollision) {
				// remove the owner entity on collision
				PhysicsPosition receiverPos = (PhysicsPosition) receiver.getComponent(PhysicsPosition.class);
				
				if(receiverPos.isReactToCollision())
					owner.removed();
			}
		}
	}

	@Override
	public void onUpdate(UpdateEvent event) {
		if(checkCollisionDurationMs != 0) {
			durationTimer += event.getDelta();
		
			if(durationTimer > checkCollisionDurationMs) {
				EventService.getInstance().removeEventListener(this);
				checkCollisionReceivers.clear();
			}
		}
		
		// check if the collision is constantly occuring to this body
		if(intervalTimer > checkCollisionIntervalMs)
			return;
		
		intervalTimer += event.getDelta();
		
		if(intervalTimer > checkCollisionIntervalMs)  {			
			List<Entity> checkCollisionReceiversCpy = new ArrayList<Entity> ();
			checkCollisionReceiversCpy.addAll(checkCollisionReceivers);
			
			for(Entity receiver : checkCollisionReceiversCpy) {
				//System.out.println(receiver.getId());
				if(!CollisionManager.getInstance().isCollidingWith(owner, receiver)) {
					checkCollisionReceivers.remove(receiver);
					continue;
				}
				EventService.getInstance().fireEvent(new DamageEvent(owner, receiver, calculateDamagePoints()));
			}

			if(checkCollisionReceivers.size() == 0) {
				// stop the continious check
				intervalTimer = checkCollisionIntervalMs + 1;
			}
			else {
				// start the timer again
				intervalTimer = 0;
			}
		}
	}
	
	@Override
	public void removed() {
		EventService.getInstance().removeEventListener(this);
	}
}
